package com.googlecode.h0v3rk4rt.net;

import java.io.*;
import java.net.*;

import com.googlecode.h0v3rk4rt.util.GameError;

public class Player {

	private int idn;
	private String id;
	private Socket socket; //TCP socket
	private ObjectInputStream ois;
	private ObjectOutputStream oos;
	private MultiplayerServer server;
	private DatagramSocket UDPServer;
	private boolean loggedIn, shutdown;

	//Sets up the player, including the UDP server
	public Player(int idnum, Socket socket, MultiplayerServer rs) {
		this.idn = idnum;
		this.id = "client"+idnum;
		this.socket = socket;
		this.server = rs;
		try {
			this.ois = new ObjectInputStream(socket.getInputStream());
			this.oos = new ObjectOutputStream(socket.getOutputStream());
		} catch (IOException e) {
			GameError.showErrorDialog(e);
		}
		server.output(id + " connected from " + socket.getInetAddress().getHostAddress());
		try {
			UDPServer = new DatagramSocket(MultiplayerServer.UDP_PORT+idn);
		} catch (SocketException e) {
			GameError.showErrorDialog(e, "Could not create UDP server at port " + (MultiplayerServer.UDP_PORT+idn), null);
		}
		(new UDP()).start();
		server.output("UDP server at port " + (MultiplayerServer.UDP_PORT+idn) + " started for " + id);
		try {
			oos.writeObject(id); //send ID to client
		} catch (IOException e) {
			e.printStackTrace();
		}
		server.output("Sending " + id + " ID...");
		(new TCP()).start();
	}

	public boolean loggedIn() {
		return loggedIn;
	}

	public void logIn() {
		loggedIn = true;
		server.output("Player " + id + " logged in.");
	}
	
	public void sendTCP(String s) {
		try {
			oos.writeObject(s);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void shutdown() {
		shutdown = true;
		try { oos.writeObject("shutdown");
			ois.close();
			UDPServer.close();
		}
		catch(IOException e) {}
	}
	
	public void joinGame() {
		if(shutdown) return;
		try {
			oos.writeObject("begin");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	//Sends data that is in vector form
	public void sendVec(double[] x, double[] v, long t) {
		send(new double[] {x[0],x[1],Math.hypot(v[0], v[1]),Math.atan2(v[1],v[0]),
				Double.doubleToRawLongBits(t) });
	}
	
	//Sends a given array of 5 doubles to the player
	public void send(double[] dArray) {
		DatagramPacket packet = NetworkingUtils.makePacket(dArray,socket.getInetAddress(),MultiplayerClient.my_UDP_PORT+idn);
		try {
			UDPServer.send(packet);
		} catch (IOException e) {
			System.out.println("Unable to send packet via UDP to " + id);
			e.printStackTrace();
		}
	}
	
	//Listens for TCP packets, and parses them using an if/else construct
	private class TCP extends Thread {
		public void run() {
			try {
				while(true) {
					String message = (String) ois.readObject();
					server.output("Message received via TCP from " + id + ":\n> " + message);
					if(message.startsWith("login")) logIn();
					else if(message.startsWith("shutdown")) server.shutdown();
					else if(message.startsWith("win")) server.processWin(idn);
				}
			} catch(Exception e) {
				if(shutdown) System.out.println("TCP server " + idn + " shut down.");
				else {
					server.shutdown();
					System.out.println("A client closed the connection.");
				}
			}
		}
	}

	//Listens for UDP packets, and sends them to be processed by the server
	private class UDP extends Thread {

		public void run() {
			DatagramPacket packet = NetworkingUtils.blankPacket();
			try {
				while(!shutdown) {
					UDPServer.receive(packet);
					server.process(NetworkingUtils.getData(packet),idn);
				}
			} catch(IOException e) {
				if(shutdown) System.out.println("UDP server " + idn + " shut down.");
				else e.printStackTrace();
			}
		}
	}
	
	public String toString() {
		return id + "\t\t" + socket.getInetAddress().getHostAddress() + "\n";
	}
}
